﻿#pragma once
#include "TimeBase.h"
#include <ctime>
#include <cstring>
#if defined(_WIN32) || defined(_WIN64)
extern "C" {
	#include <windows.h>
}
#endif

//static const char* const MONTH_NAMES[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
//static const char* const DAY_NAMES[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };


//#if defined(_WIN32) || defined(_WIN64)  // Windows.h 时
//static LARGE_INTEGER frequency;
//static bool frequencyInitialized = false;
//#endif


TimeBase::TimeBase()
	: thread_id(std::this_thread::get_id())
#if defined(_WIN32) || defined(_WIN64)
	, start_time_chrono(std::chrono::high_resolution_clock::now())
	, time_point_chrono(start_time_chrono)
#endif
{
	std::lock_guard<std::mutex> lock(mutex_);
	start_time = now_time();
	time_point = start_time;
	// mutex_和mutex_elapse_使用默认构造
	std::cout << "Copying " << program_name << " timer...\n";
}

TimeBase::TimeBase(const std::string& name)
	: thread_id(std::this_thread::get_id())
	, program_name(name)
#if defined(_WIN32) || defined(_WIN64)
	, start_time_chrono(std::chrono::high_resolution_clock::now())
	, time_point_chrono(start_time_chrono)
#endif
{
	std::lock_guard<std::mutex> lock(mutex_);
	start_time = now_time();
	time_point = start_time;
	std::cout << "Starting " << program_name << " timer...\n";
}

TimeBase::TimeBase(const TimeBase& other)
	: program_name(other.program_name)
	, thread_id(other.thread_id)
#if defined(_WIN32) || defined(_WIN64)
	, start_time_chrono(other.start_time_chrono)
	, time_point_chrono(other.time_point_chrono)
#endif
	, start_time(other.start_time)
	, time_point(other.time_point)
{
	std::cout << "Copyed " << program_name << " timer...\n";
}

TimeBase::TimeBase(TimeBase&& other) noexcept
	: program_name(std::move(other.program_name))
	, thread_id(std::move(other.thread_id))
#if defined(_WIN32) || defined(_WIN64)
	, start_time_chrono(std::move(other.start_time_chrono))
	, time_point_chrono(std::move(other.time_point_chrono))
#endif
	, start_time(std::move(other.start_time))
	, time_point(std::move(other.time_point))
{
	// mutex_ 和 mutex_elapse_ 使用默认构造
	std::cout << "Moved " << program_name << " timer...\n";
}

TimeBase& TimeBase::operator=(const TimeBase& other)
{
	if (this != &other) {
		std::lock(mutex_, other.mutex_);
		std::lock_guard<std::mutex> lock1(mutex_, std::adopt_lock);
		std::lock_guard<std::mutex> lock2(other.mutex_, std::adopt_lock);

		program_name = other.program_name;
		thread_id = other.thread_id;
#if defined(_WIN32) || defined(_WIN64)
		start_time_chrono = other.start_time_chrono;
		time_point_chrono = other.time_point_chrono;
#endif
		start_time = other.start_time;
		time_point = other.time_point;
	}
	return *this;
}

TimeBase& TimeBase::operator=(TimeBase&& other) noexcept
{
	if (this != &other) {
		std::lock(mutex_, other.mutex_);
		std::lock_guard<std::mutex> lock1(mutex_, std::adopt_lock);
		std::lock_guard<std::mutex> lock2(other.mutex_, std::adopt_lock);

		program_name = std::move(other.program_name);
		thread_id = std::move(other.thread_id);
#if defined(_WIN32) || defined(_WIN64)
		start_time_chrono = std::move(other.start_time_chrono);
		time_point_chrono = std::move(other.time_point_chrono);
#endif
		start_time = std::move(other.start_time);
		time_point = std::move(other.time_point);
		// time_point = std::exchange(other.time_point, 0); // 需要 C++14 才支持
	}
	// std::cout " << program_name << " timer...\n";
	return *this;
}

TimeBase::~TimeBase()
{
	std::lock_guard<std::mutex> lock(mutex_);
	std::cout << "Program name [" << program_name << "] run in thread ID [" << thread_id << "] Time elapsed: [" << elapsed() / 1000000.0 << "] seconds\n";
}

long long TimeBase::elapsed()
{
#if defined(_WIN32) || defined(_WIN64)
	std::lock_guard<std::mutex> lock_elapse(mutex_elapse_);
	auto end_time = std::chrono::high_resolution_clock::now();
	return std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time_chrono).count();
#else
	std::lock_guard<std::mutex> lock_elapse(mutex_elapse_);
	return now_time() - start_time;
#endif
}

void TimeBase::restart()
{
	std::lock_guard<std::mutex> lock(mutex_);
	std::cout << "Program name [" << program_name << "] run in thread ID [" << thread_id << "] Time elapsed: [" << elapsed() / 1000000.0 << "] seconds\n";
	thread_id = std::this_thread::get_id();
#if defined(_WIN32) || defined(_WIN64)
	start_time_chrono = std::chrono::high_resolution_clock::now();
#endif
	start_time = now_time();
	std::cout << "Resetting timer for thread ID: " << thread_id << "\n";
}

void TimeBase::restart(const std::string& name)
{
	std::lock_guard<std::mutex> lock(mutex_);
	std::cout << "Program name [" << program_name << "] run in thread ID [" << thread_id << "] Time elapsed: [" << elapsed() / 1000000.0 << "] seconds\n";
	program_name = name;
	thread_id = std::this_thread::get_id();
#if defined(_WIN32) || defined(_WIN64)
	start_time_chrono = std::chrono::high_resolution_clock::now();
#endif
	start_time = now_time();
	std::cout << "Resetting " << program_name << " timer for thread ID: " << thread_id << "\n";
}

inline long long TimeBase::now_time()
{
#if defined(_WIN32) || defined(_WIN64)
	// Windows 平台：使用 clock_gettime（如果支持）或 FILETIME
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309  // POSIX.1-199309
	// 使用 clock_gettime
	struct timespec ts;
	//clock_gettime(CLOCK_REALTIME) 返回的是 UTC 时间。
	clock_gettime(CLOCK_REALTIME, &ts);
	return ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
#else
	// 使用 FILETIME
	FILETIME ft;
	GetSystemTimeAsFileTime(&ft);

	// FILETIME 转换为 1900 年 1 月 1 日 00:00:00 UTC 的微秒时间戳
	ULARGE_INTEGER ul;
	ul.LowPart = ft.dwLowDateTime;
	ul.HighPart = ft.dwHighDateTime;

	// FILETIME 的基准是 1601 年 1 月 1 日 00:00:00 UTC
	// 1 个 100 纳秒为 1 个单位，转换为微秒
	return (ul.QuadPart / 10) - 11644473600000000ULL;
#endif
#else
	// Linux/macOS 平台：使用 clock_gettime
	struct timespec ts;
	clock_gettime(CLOCK_REALTIME, &ts);
	return ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
#endif
}

static void num_to_str(char* str, int num, char len)
{
	char copy_len = len;
	// 数字转字符串
	if (len > 10)
		len = 10;
	char temp[11];
	temp[len] = '\0';
	while (num > 0) {
		temp[--len] = '0' + num % 10;
		num /= 10;
	}
	while (len > 0) // 补齐字符串长度
		temp[--len] = '0';
	//std::memcpy(str, temp, copy_len);
	// 使用 strncpy 以确保不会越界
	strncpy(str, temp, copy_len);
}

inline const char* TimeBase::format(long long time_num, const char* format_str, bool long_flag)
{
	// 格式化时间：例如 %Y-%m-%d %H:%M:%S.%f %A 输出 2025-01-01 12:34:56.78 星期一
		// 传入的 time_num 微秒转格式化字符串
	static char buffer[50]; // 全局变量
	// 时间值数组：年、月、日、时、分、秒、毫秒
	short time_str[7];
	// 微秒转化为秒
	time_t seconds = time_num / 1000000LL;
	// 将秒转换为 time 结构体0
	struct tm* time_info = localtime(&seconds);
	// 提取年、月、日、时、分、秒
	time_str[0] = time_info->tm_year + 1900;	  // 年
	time_str[1] = time_info->tm_mon + 1;		  // 月
	time_str[2] = time_info->tm_mday;			  // 日
	time_str[3] = time_info->tm_hour;			  // 时
	time_str[4] = time_info->tm_min;			  // 分
	time_str[5] = time_info->tm_sec;			  // 秒
	time_str[6] = time_num % 1000000LL / 10000LL; // 10毫秒

	// 设置默认格式化
	// 长时间格式类似 %Y-%m-%d %H:%M:%S.%f
	// 短时间格式类似 %H:%M:%S.%f %A
	if (long_flag && *format_str == '\0')
		format_str = "%Y-%m-%d %H:%M:%S.%f %A";
	else if (!long_flag && *format_str == '\0')
		format_str = "%H:%M:%S.%f %A";

	/* C++ 建议使用 lambda 表达式来封装外部函数
	auto num_to_str = [](char* str, int num, char len) -> void {
		char copy_len = len;
		// 数字转字符串
		if (len > 10)
			len = 10;
		char temp[11];
		temp[len] = '\0';
		while (num > 0) {
			temp[--len] = '0' + num % 10;
			num /= 10;
		}
		while (len > 0) // 补齐字符串长度
			temp[--len] = '0';
		//std::memcpy(str, temp, copy_len);
		// 使用 strncpy 以确保不会越界
		strncpy(str, temp, copy_len);
	};
	*/

	char index = 0;
	char mod_count = 0;
	if (!long_flag)
		mod_count += 3; // 跳过年、月、日

	for (int i = 0; i < strlen(format_str); ++i)
		if (format_str[i] == '%') {
			++i;
			if (mod_count < 7)
				if (format_str[i] == 'A' || format_str[i] == 'a') {
					// 使用 strftime 函数来获取星期几
					char day_str[10];
					strftime(day_str, sizeof(day_str), "%A", time_info);
					char day_len = strlen(day_str);
					// 将获取到的星期几字符串添加到 buffer 中
					strncpy(&buffer[index], day_str, day_len);
					index += day_len;
					//--mod_count; // 星期几不计入 mod_count
				}
				else {
					num_to_str(&buffer[index], time_str[mod_count], mod_count == 0 ? 4 : 2);
					index += mod_count == 0 ? 4 : 2;
					++mod_count;
				}
		}
		else
			buffer[index++] = format_str[i];
	//for (int i = 0; i < strlen(format_str); ++i)
	//	if (format_str[i] == '%') {
	//		++i;
	//		if (mod_count < 7)
	//			if (format_str[i] == 'A' || format_str[i] == 'a') {
	//				// 使用 strftime 函数来获取星期几
	//				char day_str[10];
	//				strftime(day_str, sizeof(day_str), "%A", time_info);
	//				char day_len = strlen(day_str);
	//				// 将获取到的星期几字符串添加到 buffer 中
	//				strncpy(&buffer[index], day_str, day_len);
	//				index += day_len;
	//				//--mod_count; // 星期几不计入 mod_count
	//			}
	//			else {
	//				num_to_str(&buffer[index], time_str[mod_count], 2);
	//				index += 2;
	//				++mod_count;
	//			}
	//	}
	//	else
	//		buffer[index++] = format_str[i];
	return buffer;
}

const char* TimeBase::format_start(const char* format_str, bool long_flag) const
{
	return format(start_time, format_str, long_flag);
}

const char* TimeBase::format_point(const char* format_str, bool long_flag) const
{
	return format(time_point, format_str, long_flag);
}

void TimeBase::reset_name(const std::string& name)
{
	std::lock_guard<std::mutex> lock(mutex_);
	program_name = name;
	thread_id = std::this_thread::get_id();
	std::cout << "Reset " << program_name << " timer for thread ID: " << thread_id << " successfully\n";
}

void TimeBase::set_time_point_now() const
{
#if defined(_WIN32) || defined(_WIN64)
	const_cast<TimeBase*>(this)->time_point_chrono = std::chrono::high_resolution_clock::now();
#endif
	std::lock_guard<std::mutex> lock(mutex_);
	const_cast<TimeBase*>(this)->time_point = now_time();
}

#if defined(_WIN32) || defined(_WIN64)
const std::chrono::high_resolution_clock::time_point& TimeBase::get_time_point() const
{
	// TODO: 在此处插入 return 语句
	return time_point_chrono;
}
#endif

const long long& TimeBase::time_point_num() const
{
	std::lock_guard<std::mutex> lock(mutex_);
	return time_point;
}

const std::string& TimeBase::get_timer_name() const
{
	std::lock_guard<std::mutex> lock(mutex_);
	return program_name;
}

void TimeBase::sleep(unsigned long long microseconds)
{
	std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
}

const TimeBase& TimeBase::get_instance()
{
	static TimeBase instance;
	return instance;
}

const TimeBase& TimeBase::get_instance(const std::string& name)
{
	static TimeBase instance(name);
	return instance;
}
